"""
Test Base Module
测试基础模块 - 提供测试通用功能和工具
"""

import pytest
import asyncio
from typing import AsyncGenerator, Dict, Any, Optional
from unittest.mock import AsyncMock, MagicMock
from datetime import datetime
import uuid

from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
from sqlalchemy import text

from src.media_create.core.database import Base, get_db
from src.media_create.core.config import settings
from src.media_create.models.user import User
from src.media_create.models.generated_content import GeneratedContent, ContentStatus
from src.media_create.models.creation_request import CreationRequest
from src.media_create.models.folder import Folder
from src.media_create.models.content_tag import ContentTag


@pytest.fixture(scope="session")
def event_loop():
    """创建事件循环用于异步测试"""
    loop = asyncio.get_event_loop_policy().new_event_loop()
    yield loop
    loop.close()


@pytest.fixture(scope="session")
async def test_engine():
    """创建测试数据库引擎"""
    # 使用SQLite内存数据库进行测试
    test_db_url = "sqlite+aiosqlite:///:memory:"
    engine = create_async_engine(test_db_url, echo=False)
    
    # 创建所有表
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    
    yield engine
    
    # 清理
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.drop_all)
    await engine.dispose()


@pytest.fixture
async def test_db_session(test_engine) -> AsyncGenerator[AsyncSession, None]:
    """创建测试数据库会话"""
    SessionLocal = async_sessionmaker(
        bind=test_engine,
        class_=AsyncSession,
        expire_on_commit=False
    )
    
    async with SessionLocal() as session:
        yield session
        await session.rollback()  # 回滚事务以保持测试隔离


@pytest.fixture
async def test_user(test_db_session: AsyncSession) -> User:
    """创建测试用户"""
    user = User(
        email="test@example.com",
        username="testuser",
        full_name="Test User",
        hashed_password="hashed_password_123",
        role="user",
        status="active"
    )
    test_db_session.add(user)
    await test_db_session.commit()
    await test_db_session.refresh(user)
    return user


@pytest.fixture
async def test_admin_user(test_db_session: AsyncSession) -> User:
    """创建测试管理员用户"""
    user = User(
        email="admin@example.com",
        username="admin",
        full_name="Admin User",
        hashed_password="hashed_password_456",
        role="admin",
        status="active"
    )
    test_db_session.add(user)
    await test_db_session.commit()
    await test_db_session.refresh(user)
    return user


@pytest.fixture
async def test_content(test_db_session: AsyncSession, test_user: User) -> GeneratedContent:
    """创建测试内容"""
    content = GeneratedContent(
        user_id=test_user.id,
        title="Test Content",
        description="Test description",
        content_type="image",
        format="png",
        file_name="test.png",
        file_size_bytes=1024 * 1024,  # 1MB
        file_path="/uploads/test.png",
        ai_provider="doubao",
        ai_model="doubao-image-v1",
        status=ContentStatus.COMPLETED,
        prompt="A beautiful test image",
        generated_at=datetime.utcnow()
    )
    test_db_session.add(content)
    await test_db_session.commit()
    await test_db_session.refresh(content)
    return content


@pytest.fixture
async def test_folder(test_db_session: AsyncSession, test_user: User) -> Folder:
    """创建测试文件夹"""
    folder = Folder(
        user_id=test_user.id,
        name="Test Folder",
        description="Test folder description",
        folder_type="user",
        path="/Test Folder",
        level=0
    )
    test_db_session.add(folder)
    await test_db_session.commit()
    await test_db_session.refresh(folder)
    return folder


@pytest.fixture
async def test_tag(test_db_session: AsyncSession) -> ContentTag:
    """创建测试标签"""
    tag = ContentTag(
        name="test-tag",
        display_name="Test Tag",
        description="Test tag description",
        category="custom",
        visibility="public"
    )
    test_db_session.add(tag)
    await test_db_session.commit()
    await test_db_session.refresh(tag)
    return tag


class MockResponse:
    """模拟HTTP响应"""
    
    def __init__(self, json_data: Dict[str, Any] = None, status_code: int = 200, text: str = ""):
        self.json_data = json_data or {}
        self.status_code = status_code
        self.text = text or json.dumps(json_data)
        self.headers = {}
    
    def json(self):
        return self.json_data
    
    async def text(self):
        return self.text


class AsyncMockResponse:
    """异步模拟HTTP响应"""
    
    def __init__(self, json_data: Dict[str, Any] = None, status_code: int = 200, text: str = ""):
        self.json_data = json_data or {}
        self.status_code = status_code
        self.text_content = text or json.dumps(json_data)
        self.headers = {}
    
    async def json(self):
        return self.json_data
    
    async def text(self):
        return self.text_content


def create_mock_user(user_id: str = None, **kwargs) -> User:
    """创建模拟用户"""
    return User(
        id=uuid.UUID(user_id) if user_id else uuid.uuid4(),
        email=kwargs.get("email", "mock@example.com"),
        username=kwargs.get("username", "mockuser"),
        full_name=kwargs.get("full_name", "Mock User"),
        hashed_password=kwargs.get("hashed_password", "mock_password"),
        role=kwargs.get("role", "user"),
        status=kwargs.get("status", "active"),
        daily_generation_limit=kwargs.get("daily_generation_limit", 50),
        storage_quota_mb=kwargs.get("storage_quota_mb", 1024),
        used_storage_mb=kwargs.get("used_storage_mb", 0),
        created_at=kwargs.get("created_at", datetime.utcnow()),
        last_login_at=kwargs.get("last_login_at", datetime.utcnow())
    )


def create_mock_content(user_id: str, **kwargs) -> GeneratedContent:
    """创建模拟内容"""
    return GeneratedContent(
        id=uuid.uuid4(),
        user_id=uuid.UUID(user_id),
        creation_request_id=kwargs.get("creation_request_id"),
        folder_id=kwargs.get("folder_id"),
        title=kwargs.get("title", "Mock Content"),
        description=kwargs.get("description", "Mock description"),
        content_type=kwargs.get("content_type", "image"),
        format=kwargs.get("format", "png"),
        file_name=kwargs.get("file_name", "mock.png"),
        file_size_bytes=kwargs.get("file_size_bytes", 1024 * 1024),
        file_path=kwargs.get("file_path", "/uploads/mock.png"),
        file_url=kwargs.get("file_url"),
        width=kwargs.get("width", 1024),
        height=kwargs.get("height", 1024),
        ai_provider=kwargs.get("ai_provider", "doubao"),
        ai_model=kwargs.get("ai_model", "doubao-image-v1"),
        status=kwargs.get("status", ContentStatus.COMPLETED),
        prompt=kwargs.get("prompt", "Mock prompt"),
        generated_at=kwargs.get("generated_at", datetime.utcnow()),
        created_at=kwargs.get("created_at", datetime.utcnow()),
        updated_at=kwargs.get("updated_at", datetime.utcnow())
    )


class AsyncContextManagerMock:
    """异步上下文管理器模拟"""
    
    async def __aenter__(self):
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        pass


def assert_valid_uuid(uuid_str: str) -> bool:
    """验证UUID字符串格式"""
    try:
        uuid.UUID(uuid_str)
        return True
    except (ValueError, TypeError):
        return False


def assert_datetime_format(dt_str: str) -> bool:
    """验证日期时间字符串格式"""
    try:
        datetime.fromisoformat(dt_str.replace('Z', '+00:00'))
        return True
    except (ValueError, TypeError):
        return False


@pytest.fixture
def mock_async_function():
    """创建异步函数的mock"""
    def _create_mock(return_value=None, side_effect=None):
        mock = AsyncMock()
        if return_value is not None:
            mock.return_value = return_value
        if side_effect is not None:
            mock.side_effect = side_effect
        return mock
    return _create_mock


@pytest.fixture
def mock_file_system():
    """模拟文件系统"""
    import tempfile
    import os
    
    temp_dir = tempfile.mkdtemp()
    yield temp_dir
    
    # 清理临时文件
    import shutil
    shutil.rmtree(temp_dir, ignore_errors=True)